package com.gionee.navil.lockscreen;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.Size;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.TextureView.SurfaceTextureListener;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RemoteViews.RemoteView;

import com.gionee.navil.lockscreen.shortcut.CTextureView;
import com.gionee.navil.lockscreen.shortcut.FocusManager;
import com.gionee.navil.lockscreen.shortcut.ImageManager;
import com.gionee.navil.lockscreen.shortcut.RotateImageView;
import com.gionee.navil.lockscreen.shortcut.RotateLayout;
import com.gionee.navil.lockscreen.shortcut.Util;

@RemoteView
public class ShortcutWidgetFrame extends GnKeyguardWidgetFrame implements FocusManager.Listener,
        SurfaceTextureListener {

    private CTextureView mTextureView;
    SurfaceTexture mSurfaceTexture;
//  SurfaceView mSurfaceView;// SurfaceView的引用
//  SurfaceHolder mSurfaceHolder;// SurfaceHolder的引用
    Camera mCamera;// Camera的引用
    ImageButton mRecordButton;
    ImageButton mCameraButton;
    ImageButton mFlashButton;
    RotateImageView mThumbnailView;
    ImageView mBlankImage;
    Parameters mParameters;

    boolean mFlashOn = false;
    Thread mJpgSaving = null;
    public static final int MSG_UPDATE_THUMBNAI = 1;
    public static final int STATE_RECORD = 1;
    public static final int STATE_CAMERA = 2;
    public static final int STATE_FLASH = 3;
    public int mState = 0;
    private final AutoFocusCallback mAutoFocusCallback = new AutoFocusCallback();
    private RotateLayout mFocusAreaIndicator;
    private FocusManager mFocusManager;
    private int mPreviewFrameWidth;
    private int mPreviewFrameHeight;
    private boolean mFocusAreaSupported = false;

    Uri mUri = null;

    Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_UPDATE_THUMBNAI: {
                    updateThumbnailView((Bitmap) msg.obj);
                    break;
                }
            }
        }
    };

    private float scale = 1.0f;
    private float oldDist;
    private boolean isZoom;

    private static final int UNKNOWN = -1;
    private static final int RATIO_FACTOR_RATE = 100;
    private boolean mDeviceSupport;
    private List<Integer> mZoomRatios;
    private int mLastZoomRatio = UNKNOWN;
    private static final float ZERO = 1;
    private float mZoomIndexFactor = ZERO; // zoom rate from 1, mapping zoom gesture rate
    private static final float MIN_MOVE_DISTANCE = 30f;

    Context mContext;

    public ShortcutWidgetFrame(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mContext = context;
        init();
    }

    public ShortcutWidgetFrame(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
        mContext = context;
    }

    public ShortcutWidgetFrame(Context context) {
        super(context);
        init();
        mContext = context;
    }

    private void init() {
        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
                Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.zzzzz_gn_navil_shortcut_lineralayout, this, true);
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        Log.i("lyblyb", "onSurfaceTextureAvailable");
        // TODO Auto-generated method stub
        try {
            mSurfaceTexture = surface;
            mCamera.setPreviewTexture(mSurfaceTexture);
            mCamera.startPreview();
        } catch (Exception ioe) {
            // Something bad happened
        }
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        Log.i("lyblyb", "onSurfaceTextureDestroyed");
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
        }
        return true;
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
    }

    @Override
    protected void onFinishInflate() {
    }

    public void initCamera() {
        if (mCamera == null) {
            mCamera = Camera.open();
        }
        if (mCamera != null) {
            mParameters = mCamera.getParameters();
            List<String> ls = mParameters.getSupportedFlashModes();
            boolean flag = false;
            if (ls != null) {
                for (String flashMode : ls) {
                    if ("on".equals(flashMode)) {
                        flag = true;
                        break;
                    }
                }
            }
            if (flag) {
                mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
            }
//            mParameters.setPreviewSize(480, 480);

            Util.setOrientation(0, mCamera, mParameters);
            mCamera.setParameters(mParameters);

            Parameters parameters = mCamera.getParameters();
            Size size = parameters.getPreviewSize();
            Log.i("lyblyb", "size.height:" + size.height + " size.width:" + size.width);

            try {
                mCamera.setPreviewTexture(mSurfaceTexture);
            } catch (Exception ioe) {
            }

            onCameraParameterReady();

            mCamera.startPreview();

            mState = STATE_CAMERA;
        }
    }

    PictureCallback mJpegCallback = new PictureCallback() {
        @Override
        public void onPictureTaken(final byte[] data, final Camera camera) {
            mJpgSaving = new Thread(new Runnable() {
                public void run() {
                    storeImage(data);
                }
            });
            mJpgSaving.start();
            initCamera();
        }
    };

    public int storeImage(byte[] data) {
        try {
            long dateTaken = System.currentTimeMillis();
            String title = createName(dateTaken);
            String filename = title + ".jpg";
            int[] degree = new int[1];
            Bitmap bitmap = null;
            Size s = mParameters.getPictureSize();
            Uri uri = ImageManager.addImage(mContext.getContentResolver(), title, dateTaken, null,
                    ImageManager.getImageBucketName(), filename, null, data, degree);
            if (uri != null) {
                Log.e("lyblyb", "uri != null");
                int ratio = (int) Math.ceil((double) s.width / Util.MIN_PIC_SIZE);
                int inSampleSize = Integer.highestOneBit(ratio);
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inSampleSize = inSampleSize;
                try {
                    bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
                } catch (OutOfMemoryError e) {
                    Log.e("lyblyb", e.getMessage());
                }
                Message message = mHandler.obtainMessage();
                message.obj = bitmap;
                message.what = MSG_UPDATE_THUMBNAI;
                if (bitmap != null) {
                    mHandler.sendMessage(message);
                    Log.i("lyblyb", "mHandler.sendMessage(message)");
                }
                mUri = uri;
                Log.i("lyblyb", "uri: " + uri.getPath());
            }
            return degree[0];
        } catch (Exception ex) {
            Log.e("lyblyb", ex.getMessage());
            return 0;
        }
    }

    private String createName(long dateTaken) {
        Date date = new Date(dateTaken);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_mm_ss");
        return dateFormat.format(date);
    }

    private final class AutoFocusCallback implements android.hardware.Camera.AutoFocusCallback {
        public void onAutoFocus(boolean focused, android.hardware.Camera camera) {
            Log.i("lyblyb", "focused: " + focused);
            mFocusManager.onAutoFocus(focused);
        }
    }

    private void initializeFocusManager() {
        if (mFocusManager != null) {
            mFocusManager.removeMessages();
            mFocusManager.clearFocusOnContinuous();
        }
        mFocusManager = new FocusManager(mFocusAreaIndicator, mContext.getMainLooper(), this);
        mFocusManager.setPreviewSize(getPreviewFrameWidth(), getPreviewFrameHeight());

    }

    public void setFlashOnOrOff() {
        if (!mFlashOn) {
            mCamera.stopPreview();
            mParameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
            mCamera.setParameters(mParameters);
            mBlankImage.setVisibility(View.VISIBLE);
            mFlashOn = true;
            mState = STATE_FLASH;
            mFlashButton.setBackgroundResource(R.drawable.zzzzz_gn_navil_btn_torch_on);
        } else {
            mBlankImage.setVisibility(View.GONE);
            initCamera();
            mFlashOn = false;
            mState = STATE_CAMERA;
            mFlashButton.setBackgroundResource(R.drawable.zzzzz_gn_navil_btn_torch);
        }
    }

    private void updateThumbnailView(Bitmap bitmap) {

        Log.i("lyblyb", "updateThumbnailView 11111111");
        mThumbnailView.setBitmap(bitmap);
        mThumbnailView.setScaleType(ImageView.ScaleType.CENTER_CROP);
    }

    @Override
    public void autoFocus() {
        Log.v("lyblyb", "GN_Screen autoFocus");
        mCamera.autoFocus(mAutoFocusCallback);
    }

    @Override
    public void cancelAutoFocus() {
        Log.v("lyblyb", "GN_Screen cancelAutoFocus");
        mCamera.cancelAutoFocus();
    }

    @Override
    public void setFocusParameters() {
        updateCameraFocusAreaParameters();
    }

    public int getPreviewFrameWidth() {
        return mPreviewFrameWidth;
    }

    public int getPreviewFrameHeight() {
        return mPreviewFrameHeight;
    }

    private void updateCameraFocusAreaParameters() {
        if (mFocusAreaSupported) {
            mParameters.setFocusAreas(mFocusManager.getFocusAreas());
        }
    }

    private void initializeCapabilities() {
        Parameters parameters = mCamera.getParameters();
        mFocusAreaSupported = (parameters.getMaxNumFocusAreas() > 0 && isSupported(
                Parameters.FOCUS_MODE_AUTO, parameters.getSupportedFocusModes()));
    }

    private static boolean isSupported(String value, List<String> supported) {
        return supported == null ? false : supported.indexOf(value) >= 0;
    }

    private float spacing(MotionEvent event) {
        float x = event.getX(0) - event.getX(1);
        float y = event.getY(0) - event.getY(1);
        return FloatMath.sqrt(x * x + y * y);
    }

    public String getFilePathByUri(Context context) {
        String path = "";
        ContentResolver cr = context.getContentResolver();
        Cursor cursor = null;
        try {
            cursor = cr.query(mUri, new String[] {"_data"}, null, null, null);
            if (cursor != null && cursor.moveToFirst()) {
                path = cursor.getString(0);
            }
        } catch (Exception e) {

        } finally {
            if (cursor != null && !cursor.isClosed()) {
                cursor.close();
                cursor = null;
            }
        }
        return path;
    }

    @SuppressLint("FloatMath")
    class MulitPointTouchListener implements OnTouchListener {
        static final int NONE = 0;
        static final int DRAG = 1;
        static final int ZOOM = 2;
        int mode = NONE;
        float oldDist = 1f;

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_DOWN:
                    mode = DRAG;
                    break;
                case MotionEvent.ACTION_POINTER_DOWN:
                    oldDist = spacing(event);
                    if (oldDist > MIN_MOVE_DISTANCE) {
                        mode = ZOOM;
                    }
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_POINTER_UP:
                    if (mode == DRAG) {
                        int x = Math.round(event.getX());
                        int y = Math.round(event.getY());
                        if (mFocusManager != null && mFocusAreaSupported) {
                            mFocusManager.onSingleTapUp(x, y);
                        }
                    }
                    mode = NONE;
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (mode == ZOOM) {
                        float newDist = spacing(event);
                        if (newDist > MIN_MOVE_DISTANCE) {
                            float scale = newDist / oldDist;

                            // mZoomIndexFactor *= Math.sqrt(Math.sqrt(Math.sqrt(Math.sqrt(scale))));
                            mZoomIndexFactor *= Math.pow(scale, 0.06125);
                            if (mZoomIndexFactor <= ZERO) {
                                mZoomIndexFactor = ZERO;
                            } else if (mZoomIndexFactor >= getMaxZoomIndexFactor()) {
                                mZoomIndexFactor = getMaxZoomIndexFactor();
                            }
                            int zoomIndex = findZoomIndex(Math.round(mZoomIndexFactor * RATIO_FACTOR_RATE));
                            performZoom(zoomIndex, true);
                        }
                    }
                    break;
            }
            return true;
        }
    }

    public void onCameraParameterReady() {
        mDeviceSupport = mParameters.isZoomSupported();
        mZoomRatios = mParameters.getZoomRatios();
        int index = mParameters.getZoom();
        int curRatio = mZoomRatios.get(index);
        int finalIndex = index;
        if (mLastZoomRatio == UNKNOWN || mLastZoomRatio == curRatio) {
            mLastZoomRatio = curRatio;
            finalIndex = index;
        } else {
            finalIndex = findZoomIndex(mLastZoomRatio);
        }
        int newRatio = mZoomRatios.get(finalIndex);

        performZoom(finalIndex, newRatio != mLastZoomRatio);
    }

    private void performZoom(int zoomIndex, boolean userAction) {
        if (userAction) {
            mParameters.setZoom(zoomIndex);
            mCamera.setParameters(mParameters);
        }
    }

    private int findZoomIndex(int zoomRatio) {
        int find = 0; // if not find, return 0
        if (mZoomRatios != null) {
            int len = mZoomRatios.size();
            if (len == 1) {
                find = 0;
            } else {
                int max = mZoomRatios.get(len - 1);
                int min = mZoomRatios.get(0);
                if (zoomRatio <= min) {
                    find = 0;
                } else if (zoomRatio >= max) {
                    find = len - 1;
                } else {
                    for (int i = 0; i < len - 1; i++) {
                        int cur = mZoomRatios.get(i);
                        int next = mZoomRatios.get(i + 1);
                        if (zoomRatio >= cur && zoomRatio < next) {
                            find = i;
                            break;
                        }
                    }
                }
            }
        }
        return find;
    }

    private float getMaxZoomIndexFactor() {
        return (float) getMaxZoomRatio() / RATIO_FACTOR_RATE;
    }

    private int getMaxZoomRatio() {
        int ratio = UNKNOWN;
        if (mZoomRatios != null) {
            ratio = mZoomRatios.get(mZoomRatios.size() - 1);
        }
        return ratio;
    }

    public void onActive(boolean isActive) {
        Log.i("lyblyb", "------------>--------> Shortcut " + isActive);

        if (isActive) {
            onResume();
        } else {
            onPause();
        }
    }

    public void onResume() {
        mPreviewFrameWidth = (int) getResources().getDimension(R.dimen.zzzzz_gn_navil_preview_frame_width);
        mPreviewFrameHeight = (int) getResources().getDimension(R.dimen.zzzzz_gn_navil_preview_frame_height);

        mRecordButton = (ImageButton) findViewById(R.id.record);
        mCameraButton = (ImageButton) findViewById(R.id.camera);
        mFlashButton = (ImageButton) findViewById(R.id.flash);

        mThumbnailView = (RotateImageView) findViewById(R.id.thumbnailView);
        mBlankImage = (ImageView) findViewById(R.id.blankImg);

        mTextureView = (CTextureView) findViewById(R.id.mySurfaceView);
        mTextureView.setSurfaceTextureListener(this);

        mFocusAreaIndicator = (RotateLayout) findViewById(R.id.focus_indicator_rotate_layout);

        mCameraButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mState == STATE_CAMERA) {
                    mCamera.takePicture(null, null, mJpegCallback);
                } else if (mState == STATE_FLASH) {
                    setFlashOnOrOff();
                    initCamera();
                }
            }
        });

        mFlashButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                setFlashOnOrOff();
            }
        });

        mThumbnailView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mUri != null) {
                    Intent intent = new Intent();
                    intent.setClassName("com.gionee.navil.lockscreen",
                            "com.gionee.navil.lockscreen.shortcut.ImageScaleActivity");
                    intent.putExtra("imagePath", getFilePathByUri(mContext));
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    mContext.startActivity(intent);
                }
            }
        });

        mRecordButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mState == STATE_CAMERA) {
                    mCamera.autoFocus(mAutoFocusCallback);
                }
            }
        });

        mTextureView.setOnTouchListener(new MulitPointTouchListener());

        initializeFocusManager();

        mSurfaceTexture = mTextureView.getSurfaceTexture();

        initCamera();
        initializeCapabilities();
    }

    public void onPause() {
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
        
        if (mFocusManager != null) {
            mFocusManager.removeMessages();
            mFocusManager.clearFocusOnContinuous();
            mFocusManager = null;
        }

        mRecordButton = null;
        mCameraButton = null;
        mFlashButton = null;
        mThumbnailView = null;
        mBlankImage = null;
        mTextureView = null;
        mFocusAreaIndicator = null;
        mSurfaceTexture = null;
    }

}
